package com.nb.fly.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.nb.fly.enums.IndexEnum;
import com.nb.fly.idworker.IdWorker;
import com.nb.fly.model.Position;
import com.nb.fly.model.Shop;
import com.nb.fly.repository.ShopRepository;
import com.nb.fly.request.QueryShopRequest;
import com.nb.fly.request.SaveShopRequest;
import com.nb.fly.request.UpdateShopFinalRequest;
import com.nb.fly.request.UpdateShopRequest;
import com.nb.fly.response.ShopListVO;
import com.nb.fly.response.ShopVO;
import com.nb.fly.service.ShopService;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchScrollRequest;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.sort.GeoDistanceSortBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * ${NMAE}
 *
 * @author Gwg
 * @date 2020/6/28
 **/
@Service
public class ShopImpl implements ShopService {

    @Autowired
    private IdWorker idWorker;

    @Autowired
    private RestHighLevelClient restHighLevelClient;

    @Autowired
    private ShopRepository shopRepository;


    private final  String INDEX_NAME = "shop";

    private final  String TYPE_NAME = "shop";

    private final String SCROLL_ALIVE_TIME="1d";

    private Shop getShop(SaveShopRequest request){
        Shop shop =new Shop();
        shop.setId(idWorker.nextId());
        BeanUtils.copyProperties(request,shop);
        Position position=new Position();
        position.setLat(request.getLatitude());
        position.setLon(request.getLongitude());
        shop.setPosition(position);
        return shop;
    }

    @Override
    public void create(SaveShopRequest saveShopRequest) throws Exception {
        Shop shop = getShop(saveShopRequest);
        IndexRequest indexRequest = new IndexRequest();
        indexRequest.index(INDEX_NAME);
        indexRequest.type(TYPE_NAME);
        indexRequest.id(shop.getId().toString());

        HashMap<String,Object> source = new HashMap<>();
        source.put("Id",shop.getId());
        source.put("name",shop.getName());
        source.put("address",shop.getAddress());
        HashMap<String, Double> position = new HashMap<>();
        position.put("lat",shop.getPosition().getLat());
        position.put("lon",shop.getPosition().getLon());
        source.put("position",position);
        indexRequest.source(source);
        restHighLevelClient.index(indexRequest, RequestOptions.DEFAULT);
    }

    @Override
    public ShopListVO queryShop(QueryShopRequest request) throws Exception{
        ShopListVO response =  new ShopListVO();
        List<ShopVO> result  = new ArrayList<>();
        if (StringUtils.isEmpty(request.getScrollId())) {
            searchShopList(request, response, result);
        } else {
            searchShopScrollList(request, response, result);
        }
        return  response;
    }

    @Override
    public void update(UpdateShopRequest request) throws Exception {
        UpdateRequest updateRequest = getUpdateRequest(request);
        shopRepository.update(updateRequest);
    }

    private UpdateRequest getUpdateRequest(UpdateShopRequest request) throws  Exception{
        UpdateShopFinalRequest updateShopFinalRequest = new UpdateShopFinalRequest();
        UpdateRequest updateRequest = new UpdateRequest();
        updateRequest.index(IndexEnum.SHOP.getIndexName());
        updateRequest.type(IndexEnum.SHOP.getIndexName());
        updateRequest.timeout("10s");
        updateRequest.id(request.getId());

        Position position=new Position();
        position.setLat(request.getLatitude());
        position.setLon(request.getLongitude());
        updateShopFinalRequest.setId(request.getId());
        updateShopFinalRequest.setAddress(request.getAddress());
        updateShopFinalRequest.setPosition(position);
        updateShopFinalRequest.setName(request.getName());
        ObjectMapper objectMapper = new ObjectMapper();
        updateRequest.doc( objectMapper.readValue(objectMapper.writeValueAsString(updateShopFinalRequest),Map.class));
        //updateRequest.doc(JSONObject.parseObject(JSON.toJSONString(updateShopFinalRequest), Map.class));
        return  updateRequest;
    }
    private void searchShopList(QueryShopRequest request, ShopListVO response, List<ShopVO> result) throws Exception{
        SearchRequest searchRequest = getShopListSearchRequest(request);
        Map<String,Object>  stringObjectMap = shopRepository.shopList(searchRequest);
        ((List)stringObjectMap.get("list")).forEach(shop -> {
            result.add(JSONObject.parseObject(JSON.toJSONString(shop), ShopVO.class));
        });
        response.setList(result);
        response.setScrollId(stringObjectMap.get("scrollId").toString());
    }

    private void searchShopScrollList (QueryShopRequest request,ShopListVO response,List<ShopVO> result) throws Exception{
        SearchScrollRequest searchScrollRequest = getHospitalListSearchScrollRequest(request);
        Map<String, Object> stringObjectMap = shopRepository.shopList(searchScrollRequest);
        ((List)stringObjectMap.get("list")).forEach(shop -> {
            result.add(JSONObject.parseObject(JSON.toJSONString(shop), ShopVO.class));
        });
        response.setList(result);
        response.setScrollId(stringObjectMap.get("scrollId").toString());
    }

    private SearchRequest getShopListSearchRequest(QueryShopRequest request) {
        QueryBuilder matchAllQueryBuilder = QueryBuilders.matchAllQuery();
        GeoDistanceSortBuilder geoDistanceSort = SortBuilders.geoDistanceSort("position",request.getLatitude(),request.getLongitude());
        geoDistanceSort.order(SortOrder.ASC);
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        searchSourceBuilder.query(matchAllQueryBuilder);
        searchSourceBuilder.size(request.getSize());
        searchSourceBuilder.sort(geoDistanceSort);

        SearchRequest searchRequest = new SearchRequest();
        searchRequest.indices(INDEX_NAME);
        searchRequest.types(TYPE_NAME);
        searchRequest.scroll(SCROLL_ALIVE_TIME);
        searchRequest.source(searchSourceBuilder);
        return searchRequest;
    }

    private SearchScrollRequest getHospitalListSearchScrollRequest(QueryShopRequest request){
        SearchScrollRequest searchScrollRequest = new SearchScrollRequest();
        searchScrollRequest.scrollId(request.getScrollId());
        searchScrollRequest.scroll(SCROLL_ALIVE_TIME);
        return searchScrollRequest;
    }
}
